/**
 * 
 */
package qy.jalgotrade.broker.slippage;

import qy.jalgotrade.bar.Bar;
import qy.jalgotrade.broker.Order;

/**
 * <pre>
 * A volume share slippage model as defined in Zipline's VolumeShareSlippage model. The slippage is
 * calculated by multiplying the price impact constant by the square of the ratio of the order to
 * the total volume.
 * 
 * Check https://www.quantopian.com/help#ide-slippage for more details.
 * </pre>
 * 
 * @author c-geo
 *
 */
public class VolumeShareSlippage extends SlippageModel {

	private double __priceImpact;

	/**
	 * 
	 */
	public VolumeShareSlippage() {

		this(0.1);
	}

	/**
	 * 
	 * @param priceImpact Defines how large of an impact your order will have on the backtester's price
	 *                    calculation.
	 */
	public VolumeShareSlippage(double priceImpact) {

		super();
		__priceImpact = priceImpact;
	}

	/* (non-Javadoc)
	 * @see qy.jalgotrade.broker.slippage.SlippageModel#calculatePrice(qy.jalgotrade.broker.Order, double, double, qy.jalgotrade.bar.Bar, double)
	 */
	@Override
	public double calculatePrice(Order order, double price, double quantity, Bar bar, double volumeUsed) {

		assert bar.getVolume() > 0 : "Can't use 0 volume bars with VolumeShareSlippage";

		double totalVolume = volumeUsed + quantity;
		double volumeShare = totalVolume / bar.getVolume();

		double impactPct = Math.pow(volumeShare, 2) * __priceImpact;
		if (order.isBuy()) {
			return price * (1 + impactPct);
		} else {
			return price * (1 - impactPct);
		}
	}
}
